package zhongbo.java.air.monitor.listener;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
import zhongbo.java.air.monitor.dto.AirAlertZoneDto;
import zhongbo.java.air.monitor.dto.FlightPathDto;
import zhongbo.java.air.monitor.dto.PointDto;
import zhongbo.java.air.monitor.dto.TriggerCoordinatesDto;
import zhongbo.java.air.monitor.model.AlertLog;
import zhongbo.java.air.monitor.service.IAlertLogService;
import zhongbo.java.air.monitor.service.IJtsService;
import zhongbo.java.air.monitor.web.websocket.AlertLogWebSocket;
import zhongbo.java.air.monitor.web.websocket.LivePathWebSocket;

import java.util.Date;
import java.util.List;

/**
 * 说明：
 *
 * @author 钟波dellNotebook
 * @since 2025年04月08日 星期二 12:42:08
 */
@Component
@Slf4j
public class RedisLivePathListener implements MessageListener {

    @Autowired
    private IJtsService jtsService;

    @Autowired
    private IAlertLogService<AlertLog> alertLogService;

    @Value("${alertIntervalMinutes:1}")
    private Integer alertIntervalMinutes;

    @Override
    public void onMessage(Message message, byte[] bytes) {
        byte[] messageBody = message.getBody();
        String messageStr = new String(messageBody);
        log.info("收到实时航迹信息: {}", messageStr);
        doPublish(messageStr);
    }

    private void doPublish(String messageStr) {
        if (JSONUtil.isJson(messageStr)) {
            // 广播到websocket
            LivePathWebSocket.sendMessageToAll(messageStr);
            log.error("广播实时航迹信息到websocket: {}", messageStr);
            doAlert(messageStr);
        } else {
            log.error("收到错误的json字符串: {}", messageStr);
        }
    }

    /**
     * 计算警戒区告警
     *
     * @param messageStr 实时航迹消息
     */
    private void doAlert(String messageStr) {
        List<AirAlertZoneDto> airAlertZoneDtoList = alertLogService.listAlertZone();

        JSONObject jsonObject = JSONUtil.parseObj(messageStr);
        FlightPathDto flightPathDto = jsonObject.toBean(FlightPathDto.class);
        String icaoCode = flightPathDto.getIcaoCode();
        Double longitude = flightPathDto.getLongitude();
        Double latitude = flightPathDto.getLatitude();

        for (AirAlertZoneDto airAlertZoneDto : airAlertZoneDtoList) {
            String zoneDtoId = airAlertZoneDto.getId();
            String zoneCode = airAlertZoneDto.getZoneCode();
            String vertices = airAlertZoneDto.getVertices();
            try {
                if (StrUtil.isBlank(vertices)) {
                    log.error("无效的警戒区域! id: {}, zoneCode: {},vertices: {}", zoneDtoId, zoneCode, vertices);
                    continue;
                }
                if (!JSONUtil.isJsonArray(vertices)) {
                    log.error("无效的警戒区域! id: {}, zoneCode: {},vertices: {}", zoneDtoId, zoneCode, vertices);
                    continue;
                }
                List<PointDto> pointDtoList = jtsService.parseAlertZoneVertices(vertices);
                if (pointDtoList == null || pointDtoList.isEmpty()) {
                    log.error("无效的警戒区域! id: {}, zoneCode: {},vertices: {}", zoneDtoId, zoneCode, vertices);
                    continue;
                }
                boolean inAlertZone = jtsService.isInAlertZone(pointDtoList, longitude, latitude);
                if (inAlertZone) {
                    // 根据icao查询5分钟内有无告警记录
                    Long count = alertLogService.countMinutesByIcao(icaoCode, alertIntervalMinutes);
                    if (count == 0) {
                        // 没有有日志, 触发告警
                        AlertLog alertLog = buildAlertLog(flightPathDto, airAlertZoneDto);
                        AlertLog add = alertLogService.add(alertLog);
                        if (add != null) {
                            String jsonStr = JSONUtil.toJsonStr(alertLog);
                            log.info("成功保存告警日志: {}", jsonStr);
                            AlertLogWebSocket.sendMessageToAll(jsonStr);
                        }
                    }
                }

            } catch (Exception e) {
                log.error("计算警戒区失败!", e);
            }
        }
    }

    /**
     * 构建告警日志
     *
     * @param flightPathDto   航迹信息
     * @param airAlertZoneDto 警戒区信息
     * @return 告警日志信息
     */
    private AlertLog buildAlertLog(FlightPathDto flightPathDto, AirAlertZoneDto airAlertZoneDto) {
        AlertLog alertLog = new AlertLog();
        alertLog.setAlertZoneId(airAlertZoneDto.getId());
        alertLog.setIcaoCode(flightPathDto.getIcaoCode());
        alertLog.setAlertZoneCode(airAlertZoneDto.getZoneCode());
        alertLog.setAlertType(airAlertZoneDto.getZoneType());
        TriggerCoordinatesDto triggerCoordinatesDto = new TriggerCoordinatesDto(flightPathDto.getLongitude(), flightPathDto.getLatitude());
        String jsonStr = JSONUtil.toJsonStr(triggerCoordinatesDto);
        alertLog.setTriggerCoordinates(jsonStr);
        alertLog.setTriggerTime(new Date());
        alertLog.setStatus("未处理");
        return alertLog;
    }

}
